﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using ChessKit.Common.Primitives;
using JetBrains.Annotations;

namespace ChessKit.ChessLogics
{
	public static class BoardExtensions
	{
		/// <summary>
		/// Get the SAN (standard algebraic notation) index for a move - move number and the side to move
		/// without checking the status of the game or if it's a valid move.
		/// </summary>
		/// <returns></returns>
		public static string GetSanIndex([NotNull] this Board board)
		{
			if (board == null) throw new ArgumentNullException("board");
			var sb = new StringBuilder(5);
			sb.Append(board.MoveNumber.ToString(CultureInfo.InvariantCulture));
			if (board.SideOnMove == PieceColor.White)
			{
				sb.Append('.');
			}
			else
			{
				sb.Append("...");
			}
			return sb.ToString();
		}

		/// <summary>
		/// Gets the end of the SAN (standard algebraic notation) for a move - promotion and check/checkmate representation - after the move is made
		/// without checking the status of the game or if it's a valid move.
		/// </summary>
		/// <param name="board">The game</param>
		/// <param name="move">The move</param>
		/// <returns></returns>
		public static string GetSanEnd([NotNull] this Board board, Move move)
		{
			if (board == null) throw new ArgumentNullException("board");

			var sb = new StringBuilder(3);

			if ((move.Hint & MoveHint.Promotion) != 0)
				sb.Append('=').Append(Pt.Get(
					move.ProposedPromotion, PieceColor.White).Symbol);

      if ((move.Hint & MoveHint.GivesCheck) != 0) sb.Append('+');
			else if (board.IsMate) sb.Append('#');

			return sb.ToString();
		}

		/// <summary>
		/// Gets the begin of the SAN (standard algebraic notation) for a move - without promotion or check/checkmate representation -  before the move is made
		/// without checking the status of the game or if it's a valid move.
		/// </summary>
		/// <param name="board">The game</param>
		/// <param name="move">The move</param>
		/// <returns></returns>
		public static string GetSanBegin([NotNull] this Board board, Move move)
		{
			if (board == null) throw new ArgumentNullException("board");

			var sb = new StringBuilder(6);

			if ((move.Hint & MoveHint.KingSideCastling) == MoveHint.KingSideCastling)
			{
				sb.Append("O-O");
			}
			else if ((move.Hint & MoveHint.QueenSideCastling) == MoveHint.QueenSideCastling)
			{
				sb.Append("O-O-O");
			}
			else
			{
				if ((move.Hint & MoveHint.PawnMove) != 0)
				{
					if ((move.Hint & MoveHint.Take) != 0)
						sb.Append(move.From.File);
				}
				else
				{
					sb.Append(Pt.Get(board[move.From].Type, PieceColor.White).Symbol);

					// TODO: move should have Piece prop?
					var disambiguationList = new List<Position>(
						from m in board.GetLegalMoves()
						where m.From != move.From
						   && m.To == move.To
						   && board[move.From] == board[m.From]
						select m.From);

					if (disambiguationList.Count > 0)
					{
						if (disambiguationList.All(i => move.From.File != i.File))
						{
							sb.Append(move.From.File);
						}
            else if (disambiguationList.All(i => move.From.Rank != i.Rank))
						{
							sb.Append(move.From.Rank.ToString(CultureInfo.InvariantCulture));
						}
						else
						{
							sb.Append(move.From);
						}
					}
				}

				// if there is a capture, add capture notation
				if ((move.Hint & MoveHint.Take) == MoveHint.Take)
				{
					sb.Append('x');
				}

				// add destination square
				sb.Append(move.To);
			}

			return sb.ToString();
		}
		public static string GetSan([NotNull] this Board board, Move move)
		{
			if (board == null) throw new ArgumentNullException("board");
			return board.GetSanBegin(move) /*+ board.GetSanEnd(move)*/;
		}
		/*
				/// <summary>
				/// Gets a move from its SAN (standard algebraic notation).
				/// Throws ArgumentException if it's not a valid move.
				/// </summary>
				/// <param name="game">The game</param>
				/// <param name="san">The SAN string</param>
				/// <returns></returns>
				public static Move GetSANMove(Game game, string san)
				{
					// the game must not be null
					if (game == null) { throw new ArgumentNullException("game", Resources.NullGameMsg); }

					// the SAN string must not be null
					if (san == null) { throw new ArgumentNullException("san", Resources.NullSANMsg); }

					Move move = null;

					// if it's a short castling move
					if (san == "O-O")
					{
						foreach (Move m in game.PossibleMoves)
						{
							if (m is CastlingMove && (m.To == Board.G1 || m.To == Board.G8))
							{
								move = m;
								break;
							}
						}
					}
					// if it's a long castling move
					else if (san == "O-O-O")
					{
						foreach (Move m in game.PossibleMoves)
						{
							if (m is CastlingMove && (m.To == Board.C1 || m.To == Board.C8))
							{
								move = m;
								break;
							}
						}
					}
					else
					{
						int index = san.Length - 1;

						// remove chess and checkmate representation (if any)
						if (index > -1 && (san[index] == '+' || san[index] == '#'))
						{
							index--;
						}

						if (index < 1)
						{
							throw new ArgumentException(Resources.IllegalSANFormatMsg, "san");
						}

						// get the promotion (if any)
						char prom = '\0';
						if (san[index - 1] == '=')
						{
							prom = san[index];
							index -= 2;
						}

						if (index < 1 || san[index - 1] < 'a' || san[index - 1] > 'h' || san[index] < '1' || san[index] > '8')
						{
							throw new ArgumentException(Resources.IllegalSANFormatMsg, "san");
						}

						// get the ending square
						int to = Utils.GetPosition(san[index - 1], san[index]);
						index -= 2;


						// remove capture char (if any)
						if (index > -1 && san[index] == 'x')
						{
							index--;
						}

						// get the rank of the starting square (if any)
						int? rank = null;
						if (index > -1 && san[index] >= '1' && san[index] <= '8')
						{
							rank = GetRank(san[index]);
							index--;
						}

						// get the file of the starting square (if any)
						int? file = null;
						if (index > -1 && san[index] >= 'a' && san[index] <= 'h')
						{
							file = GetFile(san[index]);
							index--;
						}

						// get piece type char (if any)
						char pieceChar = 'P';
						if (index > -1)
						{
							pieceChar = san[index];
							index--;
						}

						// look into possible moves
						foreach (Move m in game.PossibleMoves)
						{
							if (
								m.To == to &&// the ending squares match
								(file == null || (file != null && Board.File(m.From) == file.Value)) &&// the starting squares files match (if any) 
								(rank == null || (rank != null && Board.Rank(m.From) == rank.Value)) &&// the starting squares ranks match (if any)
								pieceTypeToUpperCharConversion[game.CurrentBoard[m.From].GetType()] == pieceChar// the piece type chars match 
								)
							{
								move = m;
								break;
							}
						}

						// if it's a promotion move, set the promotion
						if (move is PromotionMove)
						{
							(move as PromotionMove).PromotionType = GetPromotionType(game.CurrentBoard.Status.WhiteTurn, prom);
						}
					}

					if (move != null)
					{
						return move;
					}
					else
					{
						throw new ArgumentException(Resources.IllegalSANMoveMsg, "san");
					}
				}

				*/




	}
}